bitkeeper revision 1.1159.1.243 (41761dd6FhmRMJyuSuwaKjjF1oicDQ)
authorkaf24@freefall.cl.cam.ac.uk <kaf24@freefall.cl.cam.ac.uk>
Wed, 20 Oct 2004 08:12:06 +0000 (08:12 +0000)
committerkaf24@freefall.cl.cam.ac.uk <kaf24@freefall.cl.cam.ac.uk>
Wed, 20 Oct 2004 08:12:06 +0000 (08:12 +0000)
Fix GDT checking so that we check ownership before zapping reserved entries
(bug pointed out by Michael Vrable). Also map_domain_mem() isn't used across
a 'goto fail' any more, so the error-exit path is now correct.

xen/arch/x86/x86_32/mm.c

index 420c3bde5ca829446ee07cc6b00d3f70b5db44dd..40acc39c81575374ae1b674d51b315b1b0e1ebed 100644 (file)
@@ -259,23 +259,39 @@ long set_gdt(struct domain *d,
              unsigned int entries)
 {
     /* NB. There are 512 8-byte entries per GDT page. */
-    int i, nr_pages = (entries + 511) / 512;
+    int i = 0, nr_pages = (entries + 511) / 512;
     struct desc_struct *vgdt;
+    unsigned long pfn;
 
-    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
-    memset( vgdt + FIRST_RESERVED_GDT_ENTRY, 0,            
-           NR_RESERVED_GDT_ENTRIES*8);
+    /* Check the first page in the new GDT. */
+    if ( (pfn = frames[0]) >= max_page )
+        goto fail;
 
-    /* Check the new GDT. */
-    for ( i = 0; i < nr_pages; i++ )
+    /* The first page is special because Xen owns a range of entries in it. */
+    if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
     {
-        if ( unlikely(frames[i] >= max_page) ||
-             unlikely(!get_page_and_type(&frame_table[frames[i]], 
-                                         d, PGT_gdt_page)) )
+        /* GDT checks failed: try zapping the Xen reserved entries. */
+        if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
+            goto fail;
+        vgdt = map_domain_mem(pfn << PAGE_SHIFT);
+        memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
+               NR_RESERVED_GDT_ENTRIES*8);
+        unmap_domain_mem(vgdt);
+        put_page_and_type(&frame_table[pfn]);
+
+        /* Okay, we zapped the entries. Now try the GDT checks again. */
+        if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
             goto fail;
     }
 
+    /* Check the remaining pages in the new GDT. */
+    for ( i = 1; i < nr_pages; i++ )
+        if ( ((pfn = frames[i]) >= max_page) ||
+             !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+            goto fail;
+
     /* Copy reserved GDT entries to the new GDT. */
+    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
     memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY, 
            gdt_table + FIRST_RESERVED_GDT_ENTRY, 
            NR_RESERVED_GDT_ENTRIES*8);